package common.util;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;

import java.util.List;
import java.util.function.Function;

/**
 * @author 米泽鹏
 */
public class PageHandler {

	private PageHandler() {
		throw new AssertionError("不可实例化");
	}

	/**
	 * 创建一个新的 Page 对象，需要提供entity转换器
	 *
	 * @param page            原有的 Page 对象
	 * @param entityConverter records内对象的转换器
	 * @param <S>             来源类型
	 * @param <T>             目标类型
	 * @return 新的 Page 对象
	 */
	public static <S, T> Page<T> convertPage(Page<S> page, Function<S, T> entityConverter) {
		Page<T> targetPage = new Page<>();
		targetPage.setCurrent(page.getCurrent());
		targetPage.setSize(page.getSize());
		targetPage.setTotal(page.getTotal());
		targetPage.setRecords(Lists.newArrayListWithCapacity(page.getRecords().size()));
		for (S source : page.getRecords()) {
			targetPage.getRecords().add(entityConverter.apply(source));
		}
		return targetPage;
	}

	/**
	 * 创建一个新的 Page 对象，只复制entity中的相同属性
	 *
	 * @param page  原有的 Page 对象
	 * @param clazz 目标类型的class对象
	 * @param <S>   来源类型
	 * @param <T>   目标类型
	 * @return 新的 Page 对象
	 */
	public static <S, T> Page<T> convertPage(Page<S> page, Class<T> clazz) {
		Page<T> targetPage = new Page<>();
		targetPage.setCurrent(page.getCurrent());
		targetPage.setSize(page.getSize());
		targetPage.setTotal(page.getTotal());
		targetPage.setRecords(Lists.newArrayListWithCapacity(page.getRecords().size()));
		for (S source : page.getRecords()) {
			T target = BeanUtil.copyProperties(source, clazz);
			targetPage.getRecords().add(target);
		}
		return targetPage;
	}

	/**
	 * 创建一个新的 Page 对象，保留原有 Page 对象的2个参数：当前页、每页条数
	 *
	 * @param page 原有的 Page 对象
	 * @param <T>  目标类型
	 * @return 新的 Page 对象
	 */
	public static <T> Page<T> createEmptyPage(Page<?> page) {
		return new Page<>(page.getCurrent(), page.getSize());
	}

	/**
	 * Page<T>类型转换，返回一个新的 page 对象，不改变原有的 page 对象。
	 *
	 * @param page 包含前端初始分页参数的 page 对象，只需含有 size 和 current
	 * @param list 类型正确但还未分页的 list
	 * @param <T>  目标类型
	 * @return 目标类型且分页的 page 对象
	 */
	public static <T> Page<T> createPageWithList(Page<?> page, List<T> list) {
		long total = list.size();
		long size = page.getSize();
		long pages = total % size == 0 ? total / size : total / size + 1;
		long current = page.getCurrent();
		// 处理切换 size 后 current 超出的情况
		if ((current - 1) * size >= total) {
			current = pages;
		}
		// 根据 size 和 current 剔除不属于当前页的记录
		List<T> finalList;
		if (total > size) {
			long fromIndex = size * (current - 1);
			long toIndex = Long.min(fromIndex + size, total);
			finalList = Lists.newArrayList(list.subList((int) fromIndex, (int) toIndex));
		} else {
			finalList = list;
		}
		Page<T> finalPage = new Page<>();
		finalPage.setTotal(total);
		finalPage.setSize(size);
		finalPage.setCurrent(current);
		finalPage.setRecords(finalList);
		return finalPage;
	}

}
